package com.itcs.box.server.service;

import com.itcs.box.BoxConstants;
import com.itcs.box.domain.BoxRequest;
import com.itcs.box.domain.BoxResponse;
import com.itcs.box.server.conf.ServerNameConstant;
import com.itcs.eureka.service.PayApiFeignClientService;
import com.itcs.se.security.data.req.BoxDncryptReq;
import com.itcs.se.security.data.req.BoxEncryptReq;
import com.itcs.se.security.data.res.BoxDncryptRes;
import com.itcs.se.security.data.res.BoxEncryptRes;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 功能描述:
 * <安全验证服务单元>
 *
 * @ClassName: SecurityService
 * @Author: wanghui
 * @Date: 2019年05月16日 20:33:53
 *
 * @Copyright: 2019 Inc. All rights reserved. 注意: 本内容仅限于内部传阅,禁止外泄以及用于其他的商业目
 */
@Component
public class SecurityService {

	private Log logger = LogFactory.getLog(getClass());

	@Resource(name="payApiRest")
	private PayApiFeignClientService apiService;

	/**是否进行安全校验*/
	@Value("${itcs.security.validate:false}")
	private boolean securityValidateFlag;

	/**免安全校验交易*/
	@Value("${itcs.unsecurity.trades:}")
	private String unsecurityTrades;

	/**免安全校验设备*/
	@Value("${itcs.unsecurity.deviceids:0}")
	private String unsecurityDeviceids;

	/**免安全校验交易*/
	private boolean validateUnsecurityTrades(String msgType) {

		if (unsecurityTrades.contains(msgType)) {
			// 免校验
			return true;
		}

		return false;
	}

	/**
	 * 作用: 明文域加密
	 * 场景:
	 * 其他:
	 * @Title plainTextEncrypt
	 * @Date: 2019-05-16 20:32
	 * @param boxResponse
	 * @return com.itcs.box.domain.BoxResponse
	 * @throws
	 */
	public BoxResponse plainTextEncrypt(BoxResponse boxResponse) {
		if (!securityValidateFlag) {
			// 免校验标识
			return boxResponse;
		}
		if (unsecurityDeviceids != "0" &
				unsecurityDeviceids.contains(boxResponse.getData().getDeviceId())) {
			return boxResponse;
		}
		String clientId = boxResponse.getData().getDeviceId();
		if (!StringUtils.isEmpty(boxResponse.getData().getPayUrl())) {
			boxResponse.getData().setPayUrl(
					this.Encrypt(0, clientId, boxResponse.getData().getPayUrl()));
		}

		return boxResponse;
	}

	/**
	 * 作用: 明文域加密解密
	 * 场景:
	 * 其他:
	 * @Title plainTextDecrypt
	 * @Date: 2019-05-16 20:33
	 * @param boxRequest
	 * @return com.itcs.box.domain.BoxRequest
	 * @throws
	 */
	public BoxRequest plainTextDecrypt(BoxRequest boxRequest) {
		if (!securityValidateFlag) {
			// 免校验标识
			return boxRequest;
		}
		if (unsecurityDeviceids != "0" & unsecurityDeviceids.contains(boxRequest.getData().getDeviceId())) {
			return boxRequest;
		}
		String clientId = boxRequest.getData().getDeviceId();
		if (!StringUtils.isEmpty(boxRequest.getData().getPayCode())) {
			boxRequest.getData().setPayCode(this.Decrypt(0, clientId, boxRequest.getData().getPayCode()));
		}

		return boxRequest;
	}

	/**
	 * 作用: 解密
	 * 场景:
	 * 其他:
	 * @Title Decrypt
	 * @Date: 2019-05-16 20:33
	 * @param encType
	 * @param clientId
	 * @param cipherText
	 * @return java.lang.String
	 * @throws
	 */
	public String Decrypt(int encType, String clientId, String cipherText) {
		BoxDncryptReq req = new BoxDncryptReq();
		req.setClientId(clientId);
		req.setCipherText(cipherText);
		req.setEncType(encType);

		Map<String, Object> resMap = this.callAdaptationService("decrypt", req);
		Object res = resMap.get(BoxConstants.BOX_RES_KEY);
		if (res != null) {
			BoxDncryptRes response = (BoxDncryptRes) resMap.get(BoxConstants.BOX_RES_KEY);
			if (response != null) {
				// 解密明文
				return response.getPlainText();
			}
		}

		return null;
	}

	// 加密
	public String Encrypt(int encType, String clientId, String plainText) {
		BoxEncryptReq req = new BoxEncryptReq();
		req.setEncType(encType);
		req.setClientId(clientId);
		req.setPlaintext(plainText);

		Map<String, Object> resMap = this.callAdaptationService("encrypt", req);
		Object res = resMap.get(BoxConstants.BOX_RES_KEY);
		if (res != null) {
			BoxEncryptRes response = (BoxEncryptRes) resMap.get(BoxConstants.BOX_RES_KEY);
			if (response != null) {
				// 明文加密
				return response.getCipherText();
			}
		}

		return null;
	}

	/**
	 * @Title: validateSecurity @Description: 安全校验 @param: @param
	 *         boxRequest @param: @return @return: boolean @throws
	 */
	public boolean validateSecurity(BoxRequest boxRequest) {
		// 免校验标识
		if (!securityValidateFlag) {
			return true;
		}

		// 免校验交易
		if (this.validateUnsecurityTrades(boxRequest.getMessgeType())) {
			return true;
		}
		
		if (unsecurityDeviceids != "0" &
				unsecurityDeviceids.contains(boxRequest.getData().getDeviceId())) {
			return true;
		}

		BoxEncryptReq req = new BoxEncryptReq();
		req.setEncType(2);
		req.setClientId(boxRequest.getData().getDeviceId());
		req.setPlaintext(this.getRequestPlainText(boxRequest));

		Map<String, Object> resMap = this.callAdaptationService("encrypt", req);
		if (boxRequest.getKey().equals(this.getCipherMac(resMap))) {
			return true;
		}
		return false;

	}

	/**
	 * @Title: getSecurityMac @Description: 获取MAC @param: @param
	 *         boxResponse @param: @return @return: String @throws
	 */
	public String getSecurityMac(BoxResponse boxResponse) {
		if (!securityValidateFlag) {
			// 免校验标识
			return "";
		}

		if (this.validateUnsecurityTrades(boxResponse.getMessgeType())) {
			// 免校验交易
			return "";
		}
		
		if (unsecurityDeviceids != "0" & unsecurityDeviceids.contains(boxResponse.getData().getDeviceId())) {
			return "";
		}

		BoxEncryptReq req = new BoxEncryptReq();
		req.setEncType(2);
		req.setClientId(boxResponse.getData().getDeviceId());
		req.setPlaintext(this.getResponsePlainText(boxResponse));

		Map<String, Object> resMap = this.callAdaptationService("encrypt", req);

		return this.getCipherMac(resMap);
	}

	private String getCipherMac(Map<String, Object> resMap) {
		Object res = resMap.get(BoxConstants.BOX_RES_KEY);
		if (res != null) {
			BoxEncryptRes response = (BoxEncryptRes) resMap.get(BoxConstants.BOX_RES_KEY);
			if (response != null) {
				// 安全校验-MAC校验
				return response.getCipherMac();
			}
		}
		return null;
	}

	private Map<String, Object> callAdaptationService(String tranId, Object request) {
		Map<String, Object> reqRecord = new HashMap<>();
		Map<String, Object> resMap = null;
		try {
			reqRecord.put(BoxConstants.BOX_REQ_KEY, request);
			resMap = apiService.exchange(ServerNameConstant.ITCS_SE_SERVER_NAME,tranId, reqRecord);
		} catch (Exception e) {
			logger.error("调用app服务失败," + e.getMessage(), e);
		}

		return resMap;
	}

	private String getRequestPlainText(BoxRequest boxRequest) {
		// 安全域
		StringBuilder plaintext = new StringBuilder();

		// 消息类型
		if (!StringUtils.isEmpty(boxRequest.getMessgeType())) {
			plaintext.append(boxRequest.getMessgeType());
		}
		// 通讯盒ID
		if (!StringUtils.isEmpty(boxRequest.getData().getDeviceId())) {
			plaintext.append(boxRequest.getData().getDeviceId())	;
		}
		// 车牌号
		if (!StringUtils.isEmpty(boxRequest.getData().getCarPlate())) {
			plaintext.append(boxRequest.getData().getCarPlate());
		}
		// 车型
		if (!StringUtils.isEmpty(boxRequest.getData().getCarClass())) {
			plaintext.append(boxRequest.getData().getCarClass());
		}
		// 通行费额
		if (!StringUtils.isEmpty(boxRequest.getData().getTollFare())) {
			plaintext.append(boxRequest.getData().getTollFare());
		}
		// 交易序列号
		if (!StringUtils.isEmpty(boxRequest.getData().getTransacSeq())) {
			plaintext.append(boxRequest.getData().getTransacSeq());
		}
		// 付款码
		if (!StringUtils.isEmpty(boxRequest.getData().getPayCode())) {
			plaintext.append(boxRequest.getData().getPayCode());
		}
		// 支付类型
		if (!StringUtils.isEmpty(boxRequest.getData().getPayType())) {
			plaintext.append(boxRequest.getData().getPayType());
		}
		// 支付结果
		if (!StringUtils.isEmpty(boxRequest.getData().getPayResult())) {
			plaintext.append(boxRequest.getData().getPayResult());
		}
		// 是否领卡
		if (!StringUtils.isEmpty(boxRequest.getData().getIsCard())) {
			plaintext.append(boxRequest.getData().getIsCard());
		}
		// 交易时间
		if (!StringUtils.isEmpty(boxRequest.getData().getTolltime())) {
			plaintext.append(boxRequest.getData().getTolltime());
		}
		// 应答结果
		if (!StringUtils.isEmpty(boxRequest.getData().getResult())) {
			plaintext.append(boxRequest.getData().getResult());
		}
		// 请求时间
		if (!StringUtils.isEmpty(boxRequest.getData().getRequestTime())) {
			plaintext.append(boxRequest.getData().getRequestTime());
		}
		// 应答时间
		if (!StringUtils.isEmpty(boxRequest.getData().getReplyTime())) {
			plaintext.append(boxRequest.getData().getReplyTime());
		}

		return plaintext.toString();
	}

	private String getResponsePlainText(BoxResponse boxResponse) {
		// 安全域
		StringBuilder plaintext = new StringBuilder();

		// 消息类型
		if (!StringUtils.isEmpty(boxResponse.getMessgeType())) {
			plaintext.append(boxResponse.getMessgeType());
		}
		// 通讯盒ID
		if (!StringUtils.isEmpty(boxResponse.getData().getDeviceId())) {
			plaintext.append(boxResponse.getData().getDeviceId());
		}
		// 车牌号
		if (!StringUtils.isEmpty(boxResponse.getData().getCarPlate())) {
			plaintext.append(boxResponse.getData().getCarPlate());
		}
		// 车型
		if (!StringUtils.isEmpty(boxResponse.getData().getCarClass())) {
			plaintext.append(boxResponse.getData().getCarClass());
		}
		// 通行费额
		if (!StringUtils.isEmpty(boxResponse.getData().getTollFare())) {
			plaintext.append(boxResponse.getData().getTollFare());
		}
		// 交易序列号
		if (!StringUtils.isEmpty(boxResponse.getData().getTransacSeq())) {
			plaintext.append(boxResponse.getData().getTransacSeq());
		}
		// 付款码
		if (!StringUtils.isEmpty(boxResponse.getData().getPayCode())) {
			plaintext.append(boxResponse.getData().getPayCode());
		}
		// 支付类型
		if (!StringUtils.isEmpty(boxResponse.getData().getPayType())) {
			plaintext.append(boxResponse.getData().getPayType());
		}
		// 支付结果
		if (!StringUtils.isEmpty(boxResponse.getData().getPayResult())) {
			plaintext.append(boxResponse.getData().getPayResult());
		}
		// 是否领卡
		if (!StringUtils.isEmpty(boxResponse.getData().getIsCard())) {
			plaintext.append(boxResponse.getData().getIsCard());
		}
		// 交易时间
		if (!StringUtils.isEmpty(boxResponse.getData().getTolltime())) {
			plaintext.append(boxResponse.getData().getTolltime());
		}
		// 应答结果
		if (!StringUtils.isEmpty(boxResponse.getData().getResult())) {
			plaintext.append(boxResponse.getData().getResult());
		}
		// 请求时间
		if (!StringUtils.isEmpty(boxResponse.getData().getRequestTime())) {
			plaintext.append(boxResponse.getData().getRequestTime());
		}
		// 应答时间
		if (!StringUtils.isEmpty(boxResponse.getData().getReplyTime())) {
			plaintext.append(boxResponse.getData().getReplyTime());
		}

		return plaintext.toString();
	}

}
